#include "server_deps.h"
#include "gm_cmd_handler.h"
#include "client_session.h"
#include "client_stat.h"
#include "server.h"
#include "bill_session.h"

#include "game_logic/mail_mgr.h"
#include "game_logic/player_data.h"
#include "game_logic/player_mgr.h"
#include "game_logic/chat_mgr.h"
#include "game_logic/rank_mgr.h"
#include "game_logic/proto_mgr.h"
#include "game_logic/world_boss.h"
#include "game_logic/pointrank.h"

#include "share/clock.h"

#include <algorithm>

string handle_pet(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;
    auto player = sess->player;
    if (NULL == player)
        return "has no player";

    int proto = get_int_arg(arg, "-t", 0);
    auto pp = new pet_t;

    const char* err = NULL;
    do {
        if (!pp->init(proto, player->n.valid_pet_serial++)) {
            --player->n.valid_pet_serial;
            err = "init err";
            break;
        }

        if (!player->add_pet(pp)) {
            err = "add err";
            break;
        }

        return "success";

    } while (0);

    pp->destroy();
    delete pp;

    return err;
}

string handle_item(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    if (NULL == sess->player)
        return "has no player";

    int proto = get_int_arg(arg, "-t", -1);
    int num = get_int_arg(arg, "-n", 0);

    if (proto < 0)
        return "invalid proto id";
    if (num <= 0)
        return "invalid num";

    sess->player->add_item(proto, num);

    return "success";
}

string handle_money(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    if (NULL == sess->player)
        return "has no player";

    int64_t money = get_int_arg(arg, "-m", 0);
    int64_t game_money = get_int_arg(arg, "-g", 0);

    if (money < 0 || game_money < 0)
        return "invalid num";

    game_money += sess->player->att(Pl8s_GameMoney);
    money += sess->player->att(Pl8s_Money);

    sess->player->att(Pl8s_GameMoney, game_money);
    sess->player->att(Pl8s_Money, money);

    return "success";
}

string handle_power(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    if (NULL == sess->player)
        return "has no player";

    int power = get_int_arg(arg, "-b", 0);

    if (power < 0)
        return "invalid num";

    power += sess->player->att(Pl4s_Power);

    sess->player->att(Pl4s_Power, power);

    return "success";
}

string handle_equip(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    if (NULL == sess->player)
        return "has no player";

    for (int i=0; i<PlayerEquipSlotNum; ++i) {
        equip_t &equip = sess->player->equip_bar[i];

        equip.equip_level = 0;
        equip.enhance_num = 0;
        memset(equip.star_num, 0, sizeof(equip.star_num));

        equip.chg = true;
    }

    sess->player->calc_equip_mod();

    return "success";
}

string handle_expet(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    if (NULL == sess->player)
        return "has no player";

    int index = get_int_arg(arg, "-i", -1);
    if (index < 0)
        return "invalid index";

    int32_t serial = sess->player->att(EPlAtt4Save(Pl4s_CombatCBegin + index));
    auto pet = sess->player->find_pet(serial);
    if (NULL == pet)
        return "invalid pet";

    //pet->att(Pe4s_StarLevel, pet->calc_star_level());
    pet->calc_att(false);

    return "success";
}

string handle_spritestar(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    auto player = sess->player;
    if (NULL == player)
        return "has no player";

    for (int i=0; i<StarProtoNum; ++i)
        player->att(EPlAtt4Save(i+Pl4s_SpriteStarBegin), EPlAtt4Save(i+Pl4s_SpriteStarBegin) + 10);

    return "success";
}

string handle_send(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    auto player = sess->player;
    if (NULL == player)
        return "has no player";

//    const char* receiver = get_str_arg(arg, "-r", "");
//    if (strlen(receiver) == 0 || receiver == NULL)
//        return "invalid receiver";
//
//    auto itr= g_playermgr->name_table.find(receiver);
//    if (itr == g_playermgr->name_table.end())
//        return "invalid receiver";
//
//
//    g_mail->send_person(player->id, itr->second, "hello");
//
    return "success";
}

string handle_query(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    auto player = sess->player;
    if (NULL == player)
        return "has no player";

//    auto itr = player->person_mails.rbegin();
//    for (int i=0; i<0; ++i) {
//        if (itr == player->person_mails.rend())
//            break;
//
//        ++itr;
//    }
//    SMailList ml;
//    for (int i=0; i<10; ++i) {
//        if (player->person_mails.rend() == itr)
//            break;
//
//        cs::OMailInfo* info = ml.add_mailinfo();
//        info->set_mailid(itr->second->mailid);
//        info->set_sender(itr->second->sender);
//        info->set_readed(itr->second->readed);
//
//        ++itr;
//    }


    return "success";
}

string handle_read(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    auto player = sess->player;
    if (NULL == player)
        return "has no player";

    int64_t mailid = get_int_arg(arg, "-i", -1);
    if (mailid < 0)
        return "invalid mailid";

//    player->do_mail(mailid, [player](mail_t* mail){
//        if (NULL == player->sess)
//            return;
//
//        SMailRead mr;
//        if (NULL != mail && mail->loaded) {
//            auto omail = mr.mutable_mail();
//            omail->set_mailid(mail->mailid);
//            omail->set_date(mail->date);
//            omail->set_content(mail->content);
//            omail->set_rewardid(mail->rewardid);
//            omail->set_rewardpct(mail->rewardpct);
//
//            mail->readed = true;
//            mail->post_save();
//        }
//    });

    return "success";
}


string handle_reward(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    auto player = sess->player;
    if (NULL == player)
        return "has no player";

    int64_t mailid = get_int_arg(arg, "-i", 0);
    if (mailid < 0)
        return "invalid mailid";

//    player->do_mail(mailid, [player](mail_t* mail){
//        if (NULL == player->sess)
//            return;
//
//        if (NULL != mail && mail->loaded && !mail->rewarded) {
//            mail->rewarded = true;
//            if (mail->rewardid >= 0) {
//                mail->post_save([mail, player](bool ok){
//                    if (NULL == player->sess)
//                        return;
//
//                    SMailReward mr;
//                    if (ok)
//                        player->reward(mail->rewardid, mr.mutable_reward(), mail->rewardpct);
//                });
//            }
//        }
//    });

    return "success";
}


string handle_del(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    auto player = sess->player;
    if (NULL == player)
        return "has no player";

    int64_t mailid = get_int_arg(arg, "-i", 0);
    if (mailid < 0)
        return "invalid mailid";

//    player->do_delmail(mailid, [mailid, player](bool ok){
//        if (NULL == player->sess)
//            return;
//
//        SMailDel md;
//        md.set_mailid(mailid);
//        md.set_ok(ok);
//    });

    return "success";
}

string handle_channel(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;

    auto player = sess->player;
    if (NULL == player)
        return "has no player";

    const char* content = get_str_arg(arg, "-c", 0);

    return "success";
}

string handle_account(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;
    if (!sess->player)
    	return "no player";
    return sess->player->account;
}

string handle_tolvl(Arg &arg, void* clientsession) {
    int tolvl = get_int_arg(arg, "-l", 0);

    const tagProtoLevel* level_proto = MAProto(Level, tolvl);
    if (NULL == level_proto) {
        return "无效关卡";
    }

    client_session_t* sess = (client_session_t*)clientsession;
    if (!sess->player) {
        return "无玩家";
    }

    sess->player->att(Pl4s_VentCurLevel, tolvl);

    return "success";
}

string handle_rank(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;
    auto player = sess->player;
    if (!player)
        "no player";
    int rank_player = -1;
    if (g_rank->player_rank.count(player->id))
        rank_player = g_rank->player_rank[player->id];

    int rank_pet = -1;
    if (g_rank->pet_rank.count(player->id))
        rank_pet = g_rank->pet_rank[player->id];
    return fmt_cstr("%d, %d", rank_player, rank_pet);
}
string handle_code(Arg &arg, void* clientsession) {
    client_session_t* sess = (client_session_t*)clientsession;
    auto player = sess->player;
    if (!player)
        "no player";

    string code = get_str_arg(arg, "-c", "");

    g_bill->use_code(sess, code);

    return "success";
}

string handle_broad(Arg &arg, void* clientsession) {
    string text = get_str_arg(arg, "-t", "");

    client_session_t* sess = (client_session_t*)clientsession;
    auto player = sess->player;

    g_chat->broad_system(text.c_str());

    return "success";
}

void handle_cworldbosscombat    (client_session_t* sess, cs::CMsg* msg);
void handle_cworldbossdata      (client_session_t* sess, cs::CMsg* msg);

string handle_worldboss(Arg &arg, void* clientsession) {

	int type = get_int_arg(arg, "-t", 0);
	switch (type) {
	case 0:
		switch (g_worldboss->status) {
		case world_boss_t::RESTING:
			g_worldboss->turnon = true;
			break;
		case world_boss_t::COMBATING:
			g_worldboss->finish = g_clock->tt_now;
			break;
		}
		break;
	case 1:
	{
		cs::CMsg msg;
		handle_cworldbossdata((client_session_t*)clientsession, &msg);
	}
		break;
	case 2:
	{
		cs::CMsg msg;
		handle_cworldbosscombat((client_session_t*)clientsession, &msg);
	}
		break;
	}

    return "success";
}

std::string handle_mail(Arg &arg, void* dummy) {
    string name = get_str_arg(arg, "-n", "");
    int32_t rewardid = get_int_arg(arg, "-r", -1);
    string content = get_str_arg(arg, "-c", "");

    const auto itr = g_playermgr->name_table.find(name);
    if (itr == g_playermgr->name_table.end()) {
    	return "no player name";
    }

    if (rewardid < 0) {
    	return "no rewardid";
    }

    g_mail->send_system(
            itr->second,
            EMT_ChargeReward,
            content.c_str(),
            rewardid,
            1.0f,
            [name, rewardid](bool ok){
                if (!ok)
                    UTIL_LOG(E, "gm mail send err to:%s rewardid:%d", name.c_str(), rewardid);
                else
                	UTIL_LOG(I, "gm mail send ok to:%s rewardid:%d", name.c_str(), rewardid);
            });

    return "success";
}

std::string handle_forbid(Arg &arg, void* dummy) {
    string name = get_str_arg(arg, "-n", "");
    int32_t forbid = get_int_arg(arg, "-f", 1);

    const auto itr = g_playermgr->name_table.find(name);
    if (itr == g_playermgr->name_table.end()) {
    	return "no player name";
    }

    g_playermgr->player_load(itr->second, [forbid](sp_player_t player){
    	if (!player)
    		return;

    	player->n.forbid = forbid;
    });

    return "success";
}

std::string handle_spriteskill(Arg &arg, void* clientsession)
{
	client_session_t* sess = (client_session_t*)clientsession;
	auto player = sess->player;
	if (!player)
		return "no player";

	auto sprite = player->sprites.get(player->cur_sprite);
	if (!sprite)
		return "no sprite";

	for (int i=0; i<SpriteSkillNum; ++i)
		sprite->skill_level[i] = 50;

	player->sprite_chg.insert(sprite->serial);

	return "success";
}

std::string handle_floor(Arg &arg, void* clientsession) {
	client_session_t* sess = (client_session_t*)clientsession;
	auto player = sess->player;
	if (!player)
		return "no player";

	int32_t floor = get_int_arg(arg, "-f", 1);
	player->att(Pl4s_MaxFloor, floor);

	return "success";
}

std::string handle_att4(Arg &arg, void* clientsession) {
	client_session_t* sess = (client_session_t*)clientsession;
	auto player = sess->player;
	if (!player)
		return "no player";

	int32_t a = get_int_arg(arg, "-a", -1);
	int32_t n = get_int_arg(arg, "-n", 0);

	if (!EPlAtt4Save_IsValid(a)) {
		return "invalid att";
	}
	player->att(EPlAtt4Save(a), n);

	return "success";
}

std::string handle_pr(Arg &arg, void* clientsession) {
	client_session_t* sess = (client_session_t*)clientsession;
	auto player = sess->player;
	if (!player)
		return "no player";

	int32_t t = get_int_arg(arg, "-t", 0);

	switch (t) {
	case 0:
		g_pr->finish = 0;
		break;
	}

	return "success";
}

bool gm_cmd_handler_t::_register_cmds() {
    bool rtv = true;

    rtv = _register_cmd("pet", "t:", handle_pet) && rtv;
    rtv = _register_cmd("item", "t:n:", handle_item) && rtv;
    rtv = _register_cmd("money", "m:g:", handle_money) && rtv;
    rtv = _register_cmd("power", "b:o:", handle_power) && rtv;
    rtv = _register_cmd("equip", "", handle_equip) && rtv;
    rtv = _register_cmd("expet", "i:", handle_expet) && rtv;
    rtv = _register_cmd("spritestar", "", handle_spritestar) && rtv;
    rtv = _register_cmd("send", "r:", handle_send) && rtv;
    rtv = _register_cmd("query", "", handle_query) && rtv;
    rtv = _register_cmd("read", "i:", handle_read) && rtv;
    rtv = _register_cmd("reward", "i:", handle_reward) && rtv;
    rtv = _register_cmd("del", "i:", handle_del) && rtv;
    rtv = _register_cmd("chat", "c:", handle_channel) && rtv;
    rtv = _register_cmd("account", "c:", handle_account) && rtv;
    rtv = _register_cmd("rank", "c:", handle_rank) && rtv;
    rtv = _register_cmd("tolvl", "l:", handle_tolvl) && rtv;
    rtv = _register_cmd("code", "c:", handle_code) && rtv;
    rtv = _register_cmd("broad", "t:", handle_broad) && rtv;
    rtv = _register_cmd("worldboss", "t:", handle_worldboss) && rtv;
    rtv = _register_cmd("mail", "n:r:c:", handle_mail) && rtv;
    rtv = _register_cmd("forbid", "n:f:", handle_forbid) && rtv;
    rtv = _register_cmd("spriteskill", "", handle_spriteskill) && rtv;
    rtv = _register_cmd("floor", "f:", handle_floor) && rtv;
    rtv = _register_cmd("att4", "a:n:", handle_att4) && rtv;
    rtv = _register_cmd("pr", "t:", handle_pr) && rtv;


    return rtv;
}
